package com.fjwt.gz.components.oss.service;

import com.alibaba.fastjson2.JSONObject;
import com.fjwt.gz.components.oss.constant.OssSavePlaceEnum;
import com.fjwt.gz.components.oss.model.OssFileConfig;
import com.fjwt.gz.core.exception.BizException;
import com.fjwt.gz.core.model.DBOSSConfig;
import com.fjwt.gz.core.service.ISysConfigService;
import com.fjwt.gz.core.utils.FileKit;
import com.obs.services.ObsClient;
import com.obs.services.ObsConfiguration;
import com.obs.services.model.AuthTypeEnum;
import com.obs.services.model.ObsObject;
import com.obs.services.model.PostSignatureRequest;
import com.obs.services.model.PostSignatureResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* 天翼云OSS 实现类
*
* @author wg
* @site https://pt.jdyd.xyz/
* @date
*/
@Service
@Slf4j
public class CtyunOssOssService implements IOssService{
    private static AuthTypeEnum authType = AuthTypeEnum.OBS;
    private static final String protocol = "https://";

    @Autowired private ISysConfigService sysConfigService;

    public ObsClient getOssClient(){
        ObsConfiguration config = new ObsConfiguration();

        DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
        config.setEndPoint(aliyunOssConfigModel.getEndpoint());
        config.setAuthType(authType);
        ObsClient  obsClient = new ObsClient(aliyunOssConfigModel.getAccessKeyId(), aliyunOssConfigModel.getAccessKeySecret(), config);

        return obsClient;
    }

    @Override
    public String upload2PreviewUrl(OssSavePlaceEnum ossSavePlaceEnum, MultipartFile multipartFile, String saveDirAndFileName) {

        try {

            DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();

            getOssClient().putObject(ossSavePlaceEnum == OssSavePlaceEnum.PUBLIC ? aliyunOssConfigModel.getPublicBucketName() : aliyunOssConfigModel.getPrivateBucketName()
                    , saveDirAndFileName, multipartFile.getInputStream());

            return genUrlHost(ossSavePlaceEnum, true, saveDirAndFileName);

        } catch (Exception e) {
           log.error("error", e.getLocalizedMessage());
            return null;
        }
    }

    @Override
    public UploadFormParams genFormParams(String bizType, OssFileConfig ossFileConfig, String saveDirAndFileName) {
          log.info("===ctyOss====");
        try {
            String fileSuffix = FileKit.getFileSuffix(saveDirAndFileName, false);

            DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();
            ObsClient obsClient = getOssClient();
            log.info("===ctyOss===obsClient="+obsClient);
            UploadFormParams result = new UploadFormParams();
            result.setFormActionUrl(this.genUrlHost(ossFileConfig.getOssSavePlaceEnum(), true, null));  //前端请求的url地址
            result.setOssFileUrl(this.genUrlHost(ossFileConfig.getOssSavePlaceEnum(), true, saveDirAndFileName));  //当上传成功 oss响应200时， 使用该路径作为文件路径
            PostSignatureRequest request = new PostSignatureRequest();
            request.setExpires(3600);
            Map<String, Object> formParams = new HashMap<String, Object>();
            String contentType="text/plain";
            if ("pdf".equals(fileSuffix)){
                contentType = "application/vnd.ms-powerpoint";
            }else if ("txt".equals(fileSuffix)){
                contentType = "text/plain;charset=utf-8";
            }
            else {
               contentType = "text/plain";
            }
            formParams.put("x-obs-acl", "public-read");
            formParams.put("content-type", contentType);
            request.setFormParams(formParams);
            PostSignatureResponse response = obsClient.createPostSignature(request);
            formParams.put("key", saveDirAndFileName);//上传的文件名
            formParams.put("policy", response.getPolicy());//policy为一段经过UTF-8和base64编码的JSON文本

            formParams.put("signature", response.getSignature());
            formParams.put("accesskeyid", aliyunOssConfigModel.getAccessKeyId());
            String postUrl = protocol + aliyunOssConfigModel.getPublicBucketName() + "." + aliyunOssConfigModel.getEndpoint();
            log.info("Creating object in browser-based way");
            log.info("\tpost url:{}",postUrl);

            result.setFormParams(new JSONObject(formParams));
            return result;
        } catch (Exception e) {
            log.error("生成上传form表单数据失败", e);
            throw new BizException(e.getMessage());
        }
    }
    private static String formUpload(String postUrl, Map<String, Object> formFields, File sampleFile, String contentType)
    {
        String res = "";
        HttpURLConnection conn = null;
        String boundary = "9431149156168";
        BufferedReader reader = null;
        DataInputStream in = null;
        OutputStream out = null;
        try
        {
            URL url = new URL(postUrl);
            conn = (HttpURLConnection)url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("User-Agent", "OBS/Test");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            out = new DataOutputStream(conn.getOutputStream());

            // text
            if (formFields != null)
            {
                StringBuffer strBuf = new StringBuffer();
                Iterator<Map.Entry<String, Object>> iter = formFields.entrySet().iterator();
                int i = 0;

                while (iter.hasNext())
                {
                    Map.Entry<String, Object> entry = iter.next();
                    String inputName = entry.getKey();
                    Object inputValue = entry.getValue();

                    if (inputValue == null)
                    {
                        continue;
                    }

                    if (i == 0)
                    {
                        strBuf.append("--").append(boundary).append("\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n");
                        strBuf.append(inputValue);
                    }
                    else
                    {
                        strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n");
                        strBuf.append(inputValue);
                    }

                    i++;
                }
                out.write(strBuf.toString().getBytes());
            }

            // file
            String filename = sampleFile.getName();
            if (contentType == null || contentType.equals(""))
            {
                contentType = "application/octet-stream";
            }

            StringBuffer strBuf = new StringBuffer();
            strBuf.append("\r\n").append("--").append(boundary).append("\r\n");
            strBuf.append("Content-Disposition: form-data; name=\"file\"; " + "filename=\"" + filename + "\"\r\n");
            strBuf.append("Content-Type: " + contentType + "\r\n\r\n");

            out.write(strBuf.toString().getBytes());

            in = new DataInputStream(new FileInputStream(sampleFile));
            int bytes = 0;
            byte[] bufferOut = new byte[1024];
            while ((bytes = in.read(bufferOut)) != -1)
            {
                out.write(bufferOut, 0, bytes);
            }

            byte[] endData = ("\r\n--" + boundary + "--\r\n").getBytes();
            out.write(endData);
            out.flush();

            // Read the returned data.
            strBuf = new StringBuffer();
            reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null)
            {
                strBuf.append(line).append("\n");
            }
            res = strBuf.toString();
        }
        catch (Exception e)
        {
            System.out.println("Send post request exception: " + e);
            e.printStackTrace();
        }
        finally
        {
            if(out != null){
                try
                {
                    out.close();
                }
                catch (IOException e)
                {
                }
            }

            if(in != null){
                try
                {
                    in.close();
                }
                catch (IOException e)
                {
                }
            }
            if(reader != null){
                try
                {
                    reader.close();
                }
                catch (IOException e)
                {
                }
            }
            if (conn != null)
            {
                conn.disconnect();
                conn = null;
            }
        }

        return res;
    }

    @Override
    public boolean downloadFile(OssSavePlaceEnum ossSavePlaceEnum, String source, String target) {

        try {

            DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();

            String bucket = ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE ? aliyunOssConfigModel.getPrivateBucketName() : aliyunOssConfigModel.getPublicBucketName();
            ObsObject obsObject = this.getOssClient().getObject(bucket,source,null);
            ReadableByteChannel rchannel = Channels.newChannel(obsObject.getObjectContent());

            ByteBuffer buffer = ByteBuffer.allocate(4096);
            WritableByteChannel wchannel = Channels.newChannel(new FileOutputStream(new File(target)));

            while (rchannel.read(buffer) != -1)
            {
                buffer.flip();
                wchannel.write(buffer);
                buffer.clear();
            }
            rchannel.close();
            wchannel.close();
            return true;
        } catch (Exception e) {
            log.error("error", e);
            return false;
        }
    }
    private static void displayTextInputStream(InputStream input)
            throws IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        while (true)
        {
            String line = reader.readLine();
            if (line == null)
                break;

            System.out.println("\t" + line);
        }
        System.out.println();

        reader.close();
    }

    /** 返回请求地址 / 文件地址 **/
    public String genUrlHost(OssSavePlaceEnum ossSavePlaceEnum, boolean isHttps, String saveDirAndFileName){

            // 私有文件 && 存在下载地址 ： 返回存储地址
           if(ossSavePlaceEnum == OssSavePlaceEnum.PRIVATE && StringUtils.isNotEmpty(saveDirAndFileName)){
               return saveDirAndFileName;
           }

        DBOSSConfig.AliyunOssConfigModel aliyunOssConfigModel = sysConfigService.getOssConfig().getAliyunOssConfigModel();

        // 公共读  or  上传action

            // 文档：https://www.alibabacloud.com/help/zh/doc-detail/39607.htm  example: https://BucketName.Endpoint/ObjectName
            return
                    ( isHttps ? "https://" : "http://" )
                    + ( ossSavePlaceEnum == OssSavePlaceEnum.PUBLIC ? aliyunOssConfigModel.getPublicBucketName() : aliyunOssConfigModel.getPrivateBucketName() )
                    + "." + aliyunOssConfigModel.getEndpoint() + "/" + StringUtils.defaultIfEmpty(saveDirAndFileName, "");
    }

}
